package org.litespring.beans.factory.support;

import org.litespring.beans.BeanDefinition;
import org.litespring.beans.PropertyValue;
import org.litespring.beans.SimpleTypeConverter;
import org.litespring.beans.factory.BeanCreationException;
import org.litespring.beans.factory.config.ConfigurableBeanFactory;
import org.litespring.util.ClassUtils;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


//这个类有两个职责，一个是读取xml生成GenericBeanDefinition类
//一个是返回一个实例，不符合单一职责，需要修改
public class DefaultBeanFactory extends DefaultSingletonBeanRegistry
                                implements  ConfigurableBeanFactory,
                                            BeanDefinitionRegistry{
//DefaultSingletonBeanRegistry判断是否实例一次
// ConfigurableBeanFactory获取  注入类加载器
// BeanDefinitionRegistry存储<bean id 的内容

    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
    private ClassLoader beanClassLoader = null;


    public void registerBeanDefinition(String beanID, BeanDefinition bd) {//BeanDefinitionRegistry的实现
        this.beanDefinitionMap.put(beanID,bd);
    }

    public BeanDefinition getBeanDefinition(String beanID) {//BeanDefinitionRegistry的实现
        return this.beanDefinitionMap.get(beanID);
    }

    //获取实体类并且为里面的属性赋值
    public Object getBean(String beanID) {//BeanFactory的实现
        BeanDefinition bd = this.getBeanDefinition(beanID);
        if(bd == null){
            throw new BeanCreationException("bean 定义不存在！");
            //--return null;
        }
        if (bd.isSingleton()){
            Object bean = this.getSingleton(beanID);//DefaultSingletonBeanRegistry
            if (bean==null){
                bean = createBean(bd);
                this.registerSingleton(beanID,bean);//DefaultSingletonBeanRegistry
            }
            return bean;
        }
        return  createBean(bd);
    }

    private Object createBean(BeanDefinition bd) {
        //创建实例
        Object bean = instantiateBean(bd);
        //设置各种类型的属性
        populateBean(bd, bean);

        return bean;

    }

    private Object instantiateBean(BeanDefinition bd) {
        if(bd.hasConstructorArgumentValues()){
            //如果有构造函数  直接用构造函数创建方法
            ConstructorResolver resolver = new ConstructorResolver(this);
            return resolver.autowireConstructor(bd);
        }else{
            ClassLoader cl = this.getBeanClassLoader();
            String beanClassName = bd.getBeanClassName();
            try {
                Class<?> clz = cl.loadClass(beanClassName);
                return clz.newInstance();
            } catch (Exception e) {
                throw new BeanCreationException("create bean for "+ beanClassName +" failed",e);
            }
        }
    }

    protected void populateBean(BeanDefinition bd, Object bean){
        List<PropertyValue> pvs = bd.getPropertyValues();
        if (pvs == null || pvs.isEmpty()) {
            return;
        }
        BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this);
        //字符串转化为boolean和integer
        SimpleTypeConverter converter = new SimpleTypeConverter();
        try{
            for (PropertyValue pv : pvs){
                String propertyName = pv.getName();
                Object originalValue = pv.getValue();
                //得到ref的实体类或者value的值
                Object resolvedValue = valueResolver.resolveValueIfNecessary(originalValue);

                BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());//jdk的方法拿到bean类的相关信息
                PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();//得到属性描述器，就是属性
                for (PropertyDescriptor pd : pds) {
                    if(pd.getName().equals(propertyName)){//属性的名字和数组中实体类的名字相等
                        Object convertedValue = converter.convertIfNecessary(resolvedValue, pd.getPropertyType());
                        pd.getWriteMethod().invoke(bean, convertedValue);//通过反射的方式，给这个属性set这个实体进去
                        break;
                    }
                }
            }
        }catch(Exception ex){
            throw new BeanCreationException("Failed to obtain BeanInfo for class [" + bd.getBeanClassName() + "]", ex);
        }
    }

    public void setBeanClassLoader(ClassLoader beanClassLoader) {
        this.beanClassLoader = beanClassLoader;
    }

    public ClassLoader getBeanClassLoader() {
        return (this.beanClassLoader!=null?this.beanClassLoader:ClassUtils.getDefaultClassLoader());
    }
}
